/**
 * 
 */
package com.py.credit.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import com.py.credit.dao.RelateDao;
import com.py.credit.entity.Column;
import com.py.credit.entity.Table;
import com.py.credit.service.ColumnService;
import com.py.credit.service.CreditConcernedService;
import com.py.credit.service.DataRelateService;
import com.py.credit.service.TableService;
import com.py.credit.utils.DateUtil;
import com.py.credit.utils.UuidUtil;

/**
 * @author dd
 *
 */
@Service
public class DataRelateServiceImpl implements DataRelateService {

	private static final Logger LOG = Logger.getLogger(DataRelateServiceImpl.class);

	@Autowired
	private RelateDao relateDao;

	@Autowired
	private ColumnService columnService;

	@Autowired
	private TableService tableService;

	@Autowired
	private CreditConcernedService creditConcernedService;

	@Override
	public List<String> getAssociationMetricCodesByDbId(int dbId) {

		return relateDao.selectAssociationMetricCodesByDbId(dbId);
	}

	@Override
	public List<String> getMajorMetricCodesByDbId(int dbId) {

		return relateDao.selectMajorMetricCodesByDbId(dbId);
	}

	@Override
	public List<Map<String, Object>> getRecordsByTableName(String tableName, String batchId,
			List<String> majorMetricCodes, int limit) {

		return relateDao.selectRecordsByTableName(tableName, batchId, majorMetricCodes, limit);
	}

	@Override
	public Map<String, String> getMatchZooUnique(int datasourceId, List<String> metricList,
			Map<String, Object> record) {

		return relateDao.selectMatchZooUnique(datasourceId, buildMatchWhereSql(metricList, record));
	}

	@Override
	public Map<String, String> getUniqueValue(int datasourceId, String tybm) {
		return relateDao.selectUniqueValue(datasourceId, tybm);
	}

	@Override
	public void updateZooUnique(int datasourceId, String tybm, Map<String, String> fillBackData) {

		relateDao.updateZooUnique(datasourceId, tybm, buildUpdateSql(fillBackData));

	}

	/**
	 * 构建MatchWhereSql AND
	 * 
	 * @param metricList
	 * @param dataMap
	 * @return MatchWhereSql
	 */
	private String buildMatchWhereSql(List<String> metricList, Map<String, Object> dataMap) {
		String matchWhereSql = "";
		// 遍历主要指标

		for (String metricCode : metricList) {
			String metricValue = (String) dataMap.get(metricCode);
			if (metricValue != null && StringUtils.isNotBlank(metricValue.toString())) {
				matchWhereSql += " AND " + metricCode + " = '" + metricValue.toString() + "'";
			}
		}
		return matchWhereSql;
	}

	private String buildUpdateSql(Map<String, String> dataMap) {

		String updateSql = "";
//        String replacement = "\\'";
		int i = 1;

		int size = dataMap.size();

		for (Entry<String, String> map : dataMap.entrySet()) {

			String key = map.getKey();

//			String value = map.getValue().replace("'", replacement);
			String value = map.getValue();

			if (i == size) {

				updateSql += key + "='" + value + "'";

			} else {

				updateSql += key + "='" + value + "',";
			}

			i++;

		}
		return updateSql;

	}

	/**
	 * 构建MatchWhereSql OR
	 * 
	 * @param metricList
	 * @param dataMap
	 * @return MatchWhereSql
	 */
	private String buildMatchORWhereSql(List<String> metricList, Map<String, ?> dataMap) {
		String matchWhereSql = "";

		int count = 0;
		for (String metricCode : metricList) {

			Object metricValue = dataMap.get(metricCode);

			if (metricValue != null && StringUtils.isNotBlank(metricValue.toString())
					&& !metricValue.toString().equalsIgnoreCase("00000000000000000x")) {
				if (count == 0) {
					matchWhereSql += " " + metricCode + " = '" + metricValue.toString() + "'";
				} else {
					matchWhereSql += " OR " + metricCode + " = '" + metricValue.toString() + "'";
				}
				count++;
			}
		}
		return matchWhereSql;
	}

	@Override
	public void unableAuth(int recordId, String tableName) {
		relateDao.unableAuth(recordId, tableName);

	}

	@Override
	public void updateRecord(String tableName, int recordId, String tybm) {
		relateDao.updateRecord(tableName, recordId, tybm);

	}

	@Override
	public void addTybmCube(String resourceId, String tybm) {
		relateDao.addTybmCube(resourceId, tybm);

	}

	@Override
	public boolean majorMatchZooUniques(int dbId, List<String> majorMetricCodes, Map<String, Object> record) {

		String buildMatchORWhereSql = buildMatchORWhereSql(majorMetricCodes, record);

		return relateDao.selectMajorMatchZooUniques(dbId, buildMatchORWhereSql) > 0;

	}

	@Override
	public void addZooRecord(Map<String, Object> record, int tableId, List<String> majorMetricCodes, int rootId,
			int deptId) {

		String metricCodeSql = "";
		String metricValueSql = "";
		for (String metricCode : majorMetricCodes) {

			Object metricValue = record.get(metricCode);
			if (metricValue != null) {
				metricCodeSql += "," + metricCode;
				metricValueSql += ",'" + metricValue.toString() + "'";
			}
		}

		relateDao.addZooRecord(rootId, deptId, tableId, (Integer) record.get("recordId"), metricCodeSql,
				metricValueSql);
	}

	@Override
	public void addZooUnique(String tybm, Map<String, Object> record, int dbId, List<String> majorMetricCodes) {

		String metricCodeSql = "";
		String metricValueSql = "";
		for (String metricCode : majorMetricCodes) {

			Object metricValue = record.get(metricCode);
			if (metricValue != null) {
				metricCodeSql += "," + metricCode;
				metricValueSql += ",'" + metricValue.toString() + "'";
			}
		}

		relateDao.addZooUnique(tybm, dbId, metricCodeSql, metricValueSql);

	}

	@Override
	public int getUnableAuthZooRecord() {

		return relateDao.selectUnableAuthZooRecord();
	}

	@Override
	public boolean exist(String resourceId, String tybm) {

		return relateDao.selectTybmCubeCount(resourceId, tybm) > 0;
	}

	@Override
	public List<String> getCommonMetricCodesByDbId(int datasourceId) {

		return relateDao.selectCommonMetricCodesByDbId(datasourceId);
	}

	@Override
	public Integer getConcernedSubjectId(String qymc) {

		return relateDao.selectConcernedSubjectId(qymc);
	}

	@Override
	public Map<String, String> relatePerform(int tableId, int kId, Map<String, Object> record, int deptId) {

		Map<String, String> map = new HashMap<String, String>();
		Table table = tableService.getTableById(tableId);
		String tableName = "t_" + table.getResourceId();
		List<String> associationMetricCodes = getAssociationMetricCodesByDbId(kId);
		// 获取公共指标
		List<String> commonMetricCodes = getCommonMetricCodesByDbId(kId);
		List<Column> tableColumns = columnService.getListByTableId(tableId);
		// 判断 表里是否包含用来关联的字段,没有跳过该表的关联操作
		boolean exist = existAssociationMetricCodes(tableColumns, associationMetricCodes);

		Map<String, String> uniqueValue = null;

		if (exist) {

			boolean skip = false;

			for (String associatecode : associationMetricCodes) {

				Object object = record.get(associatecode);

				if (object == null || StringUtils.isBlank(object.toString())) {

					skip = true;

					break;

				}

			}

			if (skip) {

				try {
					// 更新记录表中的状态 为暂时无法关联 status = T
					unableAuth((Integer) record.get("recordId"), tableName);

					// 加入record表(暂时无法关联的数据)
					addZooRecord(record, tableId, commonMetricCodes, kId, deptId);

				} catch (Exception e) {

					map.put("message", "关联字表空缺,暂时无法关时插入record表出错:表名【" + tableName + "】,数据:【" + record + "】");

					LOG.error("关联字表空缺,暂时无法关时插入record表出错:表名【" + tableName + "】,数据:【" + record + "】", e);

				}

			} else {

				try {

					// 用自动关联指标匹配unique表中的唯一记录

					uniqueValue = getMatchZooUnique(kId, associationMetricCodes, record);

				} catch (Exception e) {

					// 如果匹配了多条,做无法关联操作
					// 更新记录表中的状态 为暂时无法关联 status = T

					LOG.error("数据====>【" + record + "】与unique表中匹配出错", e);

					try {
						unableAuth((Integer) record.get("recordId"), tableName);
						// 加入record表(暂时无法关联的数据)
						addZooRecord(record, tableId, commonMetricCodes, kId, deptId);

					} catch (Exception e1) {

						LOG.error("unique表存在重复数据时做无法关联,插入record表出错:表名【" + tableName + "】,数据:【" + record + "】", e1);

					}

					map.put("message", "unique表存在重复数据时做无法关联,插入record表出错:表名【" + tableName + "】,数据:【" + record + "】");

					return map;

				}

				if (uniqueValue != null) {

					Map<String, String> fillBackData = new HashMap<String, String>();

					String tybm = uniqueValue.get("TYBM");

					if (needAssociation(record, uniqueValue, commonMetricCodes, fillBackData)) {

						boolean associateSuccess = false;
						// 补填unique表
						if (fillBackData.size() > 0) {

							try {

								updateZooUnique(kId, tybm, fillBackData);

								// 更新 数据表中的数据状态为 A已关联
								updateRecord(tableName, (Integer) record.get("recordId"), tybm);

								associateSuccess = true;

							} catch (Exception e) {

								// 更新记录表中的状态 为暂时无法关联 status = T
								// 但不加入record，字段过长也会导致失败
								unableAuth((Integer) record.get("recordId"), tableName);

								map.put("message", "回填时更新unique失败,更新记录表中的状态 为T但不加入record,表名【" + tableName + "】,数据:【"
										+ record + "】");

								LOG.error("回填时更新unique失败,更新记录表中的状态 为T但不加入record,表名【" + tableName + "】,数据:【" + record
										+ "】", e);

							}
						} else {

							// 更新 数据表中的数据状态为 A已关联
							updateRecord(tableName, (Integer) record.get("recordId"), tybm);
							associateSuccess = true;

						}

						if (associateSuccess) {

							// 如果是法人库新增关注企业数据

							try {

								if (100000 == kId) {

									String modifyTime = DateUtil.getInstance().dateToStr(new Date(),
											DateUtil.YYYY_MM_DD);

									String qymc = uniqueValue.get(associationMetricCodes.get(0));

									Integer id = getConcernedSubjectId(qymc);

									if (id != null) {

										creditConcernedService.addNewRecord(id, (Integer) record.get("recordId"),
												table.getResourceId());
										creditConcernedService.updateCheckStatus("N", id, modifyTime);

									}

								}

								// 先查询t_dc_tybm_cube是否存在相同的tybm和表名,避免同一张表里的数据相关联而产生冗余数据
								if (!exist(table.getResourceId(), tybm)) {
									// 录 t_dc_tybm_cube
									addTybmCube(table.getResourceId(), tybm);
								}

							} catch (Exception e) {

								map.put("message", "信用关注添加出错");

								LOG.error("信用关注添加出错", e);

							}
						}

					} else {

						try {

							// 更新记录表中的状态 为暂时无法关联 status = T
							unableAuth((Integer) record.get("recordId"), tableName);
							// 加入record表(暂时无法关联的数据)
							addZooRecord(record, tableId, commonMetricCodes, kId, deptId);

						} catch (Exception e) {

							map.put("message",
									"needAssociation 不符合后,暂时无法关联插入record表出错:表名【" + tableName + "】,数据:【" + record + "】");

							LOG.error(
									"needAssociation 不符合后,暂时无法关联插入record表出错:表名【" + tableName + "】,数据:【" + record + "】",
									e);

						}

					}

				} else {

					// 不匹配unique的记录

					// 数据按主要关联指标中任意一个字段(空值("",null)不算)是否存在于unique记录中

					List<String> majorMetricCodes = getMajorMetricCodesByDbId(kId);

					boolean match = majorMatchZooUniques(kId, majorMetricCodes, record);
					// 如果不存在,插入unique

					if (!match) {

						String tybm = UuidUtil.getInstance().getUUid();

						try {
							// 插入unique
							addZooUnique(tybm, record, kId, commonMetricCodes);
							// 更新 数据表中的数据状态为 A已关联
							updateRecord(tableName, (Integer) record.get("recordId"), tybm);

							// 先查询t_dc_tybm_cube是否存在相同的tybm和表名
							if (!exist(table.getResourceId(), tybm)) {
								// 录 t_dc_tybm_cube
								addTybmCube(table.getResourceId(), tybm);
							}

						} catch (Exception e) {

							// 更新 数据表中的数据状态为 T但不加入record应为是错误数据
							unableAuth((Integer) record.get("recordId"), tableName);
							map.put("message",
									"插入unique出错,数据表中的数据状态为 T但不加入record表:表名【" + tableName + "】,数据:【" + record + "】");
							LOG.error("插入unique出错,数据表中的数据状态为 T但不加入record表:表名【" + tableName + "】,数据:【" + record + "】",
									e);

						}

					} else {

						// 如果存在,则加入record表,更新数据状态为暂时无法关联

						// 更新记录表中的状态 为暂时无法关联 status = T

						try {

							unableAuth((Integer) record.get("recordId"), tableName);
							// 加入record表(暂时无法关联的数据)
							addZooRecord(record, tableId, commonMetricCodes, kId, deptId);

						} catch (Exception e) {
							map.put("message",
									"unique存在记录时,暂时无法关联插入record表出错:表名【" + tableName + "】,数据:【" + record + "】");
							LOG.error("unique存在记录时,暂时无法关联插入record表出错:表名【" + tableName + "】,数据:【" + record + "】", e);

						}

					}

				}
			}
		} else {

			map.put("message", "数据表 【" + tableName + "】不包含关联字段");

		}

		return map;
	}

	@Override
	public boolean existAssociationMetricCodes(List<Column> tableColumns, List<String> associationMetricCodes) {

		if (CollectionUtils.isEmpty(associationMetricCodes) || CollectionUtils.isEmpty(tableColumns)) {

			return false;
		}

		int hitCount = 0;

		for (String associationMetricCode : associationMetricCodes) {

			for (Column column : tableColumns) {

				if (column.getMetricCode().equals(associationMetricCode)) {

					hitCount++;
					break;

				}

			}

		}

		return hitCount == associationMetricCodes.size();
	}

	@Override
	public boolean needAssociation(Map<String, Object> dataMap, Map<String, String> uniqueValue,
			List<String> commonMetricCodes, Map<String, String> fillBackData) {
		boolean needAssociation = true;

		for (String metricCode : commonMetricCodes) {

			String newData = dataMap.get(metricCode) == null ? "" : dataMap.get(metricCode).toString();

			String oldData = uniqueValue.get(metricCode) == null ? "" : uniqueValue.get(metricCode);

			if ((StringUtils.isNotBlank(oldData) && !oldData.equals(newData) && StringUtils.isNotBlank(newData))) {

				if (newData.equalsIgnoreCase("00000000000000000x") || oldData.equalsIgnoreCase("00000000000000000x")) {

					continue;

				}

				needAssociation = false;

				break;

			}

			if (StringUtils.isNotBlank(newData) && StringUtils.isBlank(oldData)
					&& !newData.equalsIgnoreCase("00000000000000000x")) {

				fillBackData.put(metricCode, newData);

			}

		}

		return needAssociation;
	}

	@Override
	public Integer batchRelatePerform(String batchId, String tableName, String datasourceId, String tableId,
			String deptId) {

		return relateDao.callProcedure(batchId, tableName, datasourceId, tableId, deptId);

	}

	@Override
	public int getWaitCountByBatchId(String tableName, String batchId) {

		return relateDao.selectWaitCountByBatchId(tableName, batchId);
	}

	@Override
	public void addDummyZooUniqueIfNoData(int datasourceId) {

		if (relateDao.selectUniqueCount(datasourceId) == 0) {

			// 现在只支持三个库

			String keyword = null;

			if (datasourceId == 100000) {

				keyword = "A000001";

			} else if (datasourceId == 100001) {

				keyword = "B000002";

			} else if (datasourceId == 100002) {

				keyword = "C000001";
			}

			relateDao.addDummyZooUnique(datasourceId, keyword);

		}

	}

	@Override
	public void deleteDummyZooUnique(int datasourceId) {

		relateDao.deleteDummyZooUnique(datasourceId);

	}

}
